package com.wm.blog_gateway.filter;

import com.wm.blog_common.constatnt.CommonConstant;
import com.wm.blog_common.constatnt.ContextConstant;
import com.wm.blog_common.constatnt.ErrorConstant;
import com.wm.blog_common.context.AdminBaseContextHandler;
import com.wm.blog_gateway.auth.AdminDetailsServiceImpl;
import com.wm.blog_gateway.auth.UserDetailsImpl;
import com.wm.blog_gateway.config.GatewayWhiteConfig;
import com.wm.blog_gateway.config.JwtProperties;
import com.wm.blog_gateway.config.JwtTokenUtil;
import com.wm.blog_gateway.exception.NoAuthException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

/***
 * @ClassName: AuthorityFilter
 * @Description:权限校验拦截器   结合jwt,给security使用
 * @Author: 半卷流年
 * @Create_time: 16:26 2020-3-28
 */
@Configuration
@Slf4j
@AllArgsConstructor
public class AuthorityFilter implements WebFilter {


    private final GatewayWhiteConfig gatewayWhiteConfig;

    private final JwtProperties jwtProperties;

    private final JwtTokenUtil jwtTokenUtil;

    private final AdminDetailsServiceImpl adminDetailsService;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        //获取当前请求的url
        String requestUrl = exchange.getRequest().getURI().getPath();
        if(this.checkWhiteUrl(requestUrl)){
            //放行请求
            return chain.filter(exchange);
        }else{
            //获取请求头
            String authHeader = this.getRequestHeader(jwtProperties.getTokenHeader(), exchange.getRequest());
            //token必须以Beare开头,排除白名单请求
            log.info("访问url:{},token:{}",requestUrl,authHeader);
            if (ObjectUtils.isNotEmpty(authHeader) && authHeader.startsWith(CommonConstant.TOKEN_PREFIX)) {
                //截取token
                final String authToken = authHeader.substring(CommonConstant.TOKEN_PREFIX.length() );
                //冲token中获取到username
                String username = jwtTokenUtil.getUserNameFromToken(authToken);
                if (ObjectUtils.isNotEmpty(username) && SecurityContextHolder.getContext().getAuthentication() == null) {
                    //获取到用户信息
                    UserDetailsImpl userDetail = adminDetailsService.getUserDetail(username);
                    //校验token是否过期
                    if (jwtTokenUtil.validateToken(authToken,userDetail)) {
                        //将未过期的信息存入
                        exchange.getAttributes().put(CommonConstant.ADMIN,String.valueOf(userDetail.getId()));
                        exchange.getAttributes().put(CommonConstant.ADMIN_NAME,username);
                        //存入token,因激活邮件的参数需要
                        exchange.getAttributes().put(CommonConstant.AMIND_Authorization,authHeader);
                    }else{
                        throw new NoAuthException(ErrorConstant.TOKEN_EXPIRE);
                    }
                }else{
                    //抛出异常
                    throw new NoAuthException(ErrorConstant.TOKEN_EXPIRE);
                }
            }else{
                //无权限
                throw new NoAuthException(ErrorConstant.TOKEN_EMPTY);
            }
        }

        //放行请求
        return chain.filter(exchange);
    }


    /**
     * 校验不需要
     * @return
     */
    private boolean checkWhiteUrl(String url){
        List<String> list = Optional
                .ofNullable(gatewayWhiteConfig.getWhiteList())
                .orElse(Collections.emptyList());
        //放行 /actuator 相关接口,spring boot admin 需要访问
        if(url.contains("actuator")){
            return true;
        }
        return list.contains(url);
    }


    /**
     * 获取指定的请求头数据
     * @return
     */
    private String getRequestHeader(String headName,ServerHttpRequest request){
        List<String> list = request.getHeaders().get(headName);
        return CollectionUtils.isNotEmpty(list) ? list.get(0):null;
    }

}
